﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Effects.Effects;
using Effects.Effects.GuiParts;

namespace EffectsPack
{
    /// <summary>
    ///  Volume boost. Amplifies signal by user controlled level.
    /// </summary>
    public class Boost:Effect
    {
        #region controls

        #region footswitch
        // switch for turning the effect ON or OFF

        /// <summary>
        ///  Footswitch for turning the effect On/Off.
        /// </summary>
        private Footswitch footswitch;

        /// <summary>
        ///  Key for the footswitch setting.
        /// </summary>
        /// <remarks>
        ///  Key that identifies footswitch setting. This key will be later used in methods that handle recording changes in parameter settings.
        ///  Remeber that every key must be unique.
        /// </remarks>
        private const int footswitchKey = 0;

        /// <summary>
        ///  Indicates On/Off status of the effect.
        /// </summary>
        private LED led;

        /// <summary>
        ///  Synchornizes led with footswitch.
        /// </summary>
        /// <remarks>
        ///  Useful class that keeps synchornized footswitch and Led for us.
        /// </remarks>
        private FootswitchLedSynchronizer synchronizer;

        #endregion

        #region boost

        /// <summary>
        ///  Boost level.
        /// </summary>
        private double boost;

        /// <summary>
        ///  Controls boost level
        /// </summary>
        private Pot BoostPot;

        /// <summary>
        ///  Key for the boost parameter
        /// </summary>
        private const int boostKey = 1;

        #endregion

        #endregion
       
        #region effects_properties

        /// <summary>
        ///  Gets the name of the effect.
        /// </summary>
        public override string Name
        {
            get
            {
                return "Boost v1.0";
            }
        }

        /// <summary>
        ///  Turns the effect On/Off.
        /// </summary>
        public override bool Switch
        {
            get
            {
                return base.Switch;
            }
            set
            {
                base.Switch = value;

                // synchronizer sets the value to the LED and footswitch
                synchronizer.SetValue(value);
            }
        }

        #endregion

        #region constructor

        /// <summary>
        ///  Creates new instance.
        /// </summary>
        public Boost()
        {
            BackgroundImage = System.Drawing.Image.FromStream(new System.IO.MemoryStream(Properties.Resources.Boost));
            Size = BackgroundImage.Size;
            InitializeComponents();
            InitializeFootswitch();
        }

        /// <summary>
        ///  Initializes pot.
        /// </summary>
        private void InitializeComponents()
        {
            BoostPot = new Pot();
            BoostPot.MaxValue = 10;
            BoostPot.MinValue = 1;
            BoostPot.Knob = PotKnob.ChickenKnob;
            BoostPot.Location = new System.Drawing.Point(20, 50);
            BoostPot.ValueChanged += new PotValueChangedEventHandler(BoostPot_moved);
            Controls.Add(BoostPot);
            BoostPot.Reset();

       }

        /// <summary>
        ///  Initializes footswitch and led.
        /// </summary>
        private void InitializeFootswitch()
        {
            // footswitch
            footswitch = new Footswitch();
            switchedOn = true;
            footswitch.On = true;
            footswitch.Switched += new FootswitchSwitchedEventHandler(this.FootswitchSwitched);
            footswitch.Location = new System.Drawing.Point(110, 146);
            Controls.Add(footswitch);

            // led
            led = new LED();
            led.On = true;
            led.Location = new System.Drawing.Point(65, 30);
            Controls.Add(led);

            // synchronization between LED and footswitch
            synchronizer = new FootswitchLedSynchronizer(footswitch, led);
        }

        #endregion

        #region main_work

        /// <summary>
        ///  Effects input signal.
        /// </summary>
        /// <param name="data"> Input signal </param>
        /// <returns> Effected output signal </returns>
        public override double[] effect(double[] data)
        {
            if (switchedOn)
            {
                double[] retData = new double[data.Length];
                for (int i = 0; i < data.Length; i++)
                {
                    retData[i] = boost * data[i];
                }
                return retData;
            }

            return data;
        }

        #endregion

        #region controls_event_handlers

        /// <summary>
        ///  Boost pot event handler
        /// </summary>
        /// <param name="sender"> Object that raised the event </param>
        /// <param name="e"> Event arguments. </param>
        private void BoostPot_moved(object sender, PotValueChangedEventArgs e)
        {
            boost = e.NewValue;
            EffectSettingsChangedEventArgs changeArgs = new EffectSettingsChangedEventArgs(boostKey, boost);
            if (SettingsChanged != null)
                SettingsChanged(this, changeArgs);
        }

        /// <summary>
        ///  Footswitch.Switched event handler. Turns effect On or Off accordingly to the event arguments.
        /// </summary>
        /// <param name="sender"> Object that has raised the event </param>
        /// <param name="args"> Event arguments </param>
        protected void FootswitchSwitched(object sender, FootswitchSwitchedEventArgs args)
        {
            this.switchedOn = args.On;

            EffectSettingsChangedEventArgs changeArgs = new EffectSettingsChangedEventArgs(footswitchKey, switchedOn);
            if (SettingsChanged != null)
                this.SettingsChanged(this, changeArgs);
        }

        #endregion

        #region settings
        // Getting and setting the settings of volume effect

        /// <summary>
        ///  Raised when any parameter of effect is changed.
        /// </summary>
        /// <remarks> 
        ///  We raise this event whenewer user changes any control (Volume pot or footswitch).
        /// </remarks>
        public override event EffectSettingsChangedDelegate SettingsChanged;

        /// <summary>
        ///  Sets settings 
        /// </summary>
        /// <param name="e"> Settings that are to be changed </param>
        public override void SetSetting(EffectSettingsChangedEventArgs e)
        {
            // all keys in this class are integers
            int key = (int)e.Key;

            // is it volume settings?
            if (key == boostKey)
            {
                boost = (double)e.Value;
                BoostPot.SetValue(boost);
                return;
            }

            // is it footswitch settings?
            if (key == footswitchKey)
            {
                switchedOn = (bool)e.Value;
                synchronizer.SetValue(switchedOn);
                return;
            }
        }

        /// <summary>
        ///  Gets all current settings.
        /// </summary>
        /// <returns> All current settings </returns>
        /// <remarks>
        ///  We return array that contains all current settings of the effect. In our case it means, volume level and footswitch state.
        ///  Note the order of parameters in the array is the same as is returned by GetParameters method.
        /// </remarks>
        public override object[] GetAllSettings()
        {
            object[] settings = new object[2];
            settings[0] = switchedOn;
            settings[1] = boost;
            return settings;
        }

        /// <summary>
        ///  Sets all settings.
        /// </summary>
        /// <param name="settings"> Settings to set. This argument should be taken from GetAllSettings previously </param>
        /// <remarks>
        ///  We set all parameters. Passed array has the same structure as the one returned by GetAllSettings method.
        /// </remarks>
        public override void SetAllSettings(object[] settings)
        {
            object[] sets = (object[])settings;

            switchedOn = (bool)sets[0];
            synchronizer.SetValue(switchedOn);

            boost = (double)sets[1];
            BoostPot.SetValue(boost);
        }


        /// <summary>
        ///  Gets array containing all effect's parameters.
        /// </summary>
        /// <returns> Array containing description fo all parameters </returns>
        /// <remarks>
        ///  In here we describe all parameters of the effect. Remember that order of them in returned array is important and same order
        ///  must be used in GetAllSettings and GetAllSettings methods.
        /// </remarks>
        public override EffectParam[] GetParameters()
        {
            // we have two parameters
            EffectParam[] parameters = new EffectParam[2];

            /* footswitch settings: we describe it as list type, with two values
             *    To which we set string and value */
            ListItem[] footswitchState = new ListItem[2];
            footswitchState[0] = new ListItem("Turn on", true);
            footswitchState[1] = new ListItem("Turn off", false);

            /*  parameters ar described by key, string displayed to the user and bounds (or list enumeration)
             * Note that for volume parameter we must pass float value to use appropriate constructor */
            parameters[0] = new EffectParam(footswitchKey, "ON/OFF", footswitchState);
            parameters[1] = new EffectParam(boostKey, "Boost level", 0F, 5F);

            return parameters;
        }

        #endregion
    }
}
